package com.yylending.las.common.widgets;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;

import com.yyfax.common.tools.DensityUtil;
import com.yylending.las.R;

import java.text.DecimalFormat;

/**
 * 自定义水平进度条
 */
public class HorizontalProgressBar extends View {

    // 最小刻度(最小期数)
    private static final int MIN_SCALE = 1;
    /**
     * 三角形三个顶点的坐标
     */
    private int mTriangleVertexOne;
    private int mTriangleVertexTwo;
    private int mTriangleVertexThree;
    private int mWidth;
    private int mHeight;
    private float mViewHeight;
    private int mScaleTextLeftMargin;
    private int mScaleTextRightMargin;
    // 是否启动动画
    private boolean mEnableAnim = false;
    // 左边距
    private float mLeftPos;
    // 右边距
    private float mRightPos;
    private Paint mProgressBgPaint;
    private Paint mProgressPaint;
    private Paint mDotPaint;
    private Paint mIndicateDotPaint;
    private Paint mTipPaint;
    private Paint mTipTextPaint;
    private Paint mSquarePaint;
    private Paint mScaleTextPaint;
    private float mShadowWidth;
    private Rect mTipTextRect = new Rect();
    private String mTipText = "0";
    // 起始刻度文字
    private String mLeftScaleText = "";
    // 最大刻度文字.
    private String mRightScaleText = "";
    private Rect mScaleTextRect = new Rect();
    private float mScaleTextH;
    /**
     * 进度条上的刻度圆点半径
     */
    private float mDotRadius;
    /**
     * 正方形指示框中间圆点的半径
     */
    private float mIndicateDotRadius;
    /**
     * 渐变颜色
     */
    private int[] mGradientColors = {Color.parseColor("#5598f9"), Color.parseColor("#4b7cf9")};
    /**
     * 进度
     */
    private float mProgress;
    /**
     * 进度条高度
     */
    private float mProgressPaintH;
    /**
     * 动画执行时间
     */
    private int mDuration;
    /**
     * 百分比提示框画笔的宽度
     */
    private float mTipPaintWidth;
    /**
     * 提示框的高度
     */
    private float mTipHeight;
    /**
     * 提示框的宽度
     */
    private float mTipWidth;
    /**
     * 画三角形的path
     */
    private Path mPath = new Path();
    /**
     * 三角形的高
     */
    private float mTriangleHeight;
    /**
     * 进度条距离提示框的高度
     */
    private float mProgressMarginTop;

    /**
     * 刻度文字距上边距离
     */
    private float mScaleTextMarginTop;
    /**
     * 正方形框边长
     */
    private float mSquareWidth;
    /**
     * 进度移动的距离
     */
    private float mMoveDis;
    /**
     * 百分比文字字体大小
     */
    private float mTipTextPaintSize;
    /**
     * 进度条背景颜色
     */
    private int mProgressBgColor;
    /**
     * 进度条颜色
     */
    private int mProgressColor;
    /**
     * 进度知识正方形中间的圆点颜色.
     */
    private int mIndicateDotColor;
    /**
     * 刻度文字的颜色
     */
    private int mScaleTextColor;
    /**
     * 绘制提示框的矩形
     */
    private RectF mRectF = new RectF();
    /**
     * 绘制进度条上的圆角正方形
     */
    private RectF mSquareRectF = new RectF();
    /**
     * 圆角矩形的圆角半径
     */
    private float mRoundRectRadius;
    /**
     * 进度监听回调
     */
    private ProgressListener mProgressListener;

    public HorizontalProgressBar(Context context) {
        super(context);
    }

    public HorizontalProgressBar(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
        initPaint();
    }

    /**
     * 格式化数字(保留两位小数)
     *
     * @param money
     * @return
     */
    public static String formatNumTwo(double money) {
        DecimalFormat format = new DecimalFormat("0.00");
        return format.format(money);
    }

    /**
     * 格式化数字(保留一位小数)
     *
     * @param money
     * @return
     */
    public static String formatNum(int money) {
        DecimalFormat format = new DecimalFormat("0");
        return format.format(money);
    }

    public static int format2Int(double i) {
        return (int) i;
    }

    /**
     * 初始化画笔宽度及view大小
     */
    private void init(Context context, @Nullable AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HorizontalProgressBar);
        mProgressBgColor = typedArray.getColor(R.styleable.HorizontalProgressBar_progressBgColor, 0xFFcadaff);
        mProgressColor = typedArray.getColor(R.styleable.HorizontalProgressBar_progressColor, 0xFF4b7cf9);
        mIndicateDotColor = typedArray.getColor(R.styleable.HorizontalProgressBar_indicateDotColor, 0xFFFFFFFF);
        mScaleTextColor = typedArray.getColor(R.styleable.HorizontalProgressBar_scaleTextColor, 0xff666666);

        mTipTextPaintSize = typedArray.getDimension(R.styleable.HorizontalProgressBar_tipTextPaintSize, DensityUtil.sp2px(context, 12));
        mTipHeight = typedArray.getDimension(R.styleable.HorizontalProgressBar_tipHeight, DensityUtil.dipToPixels(context, 25));
        mTipWidth = typedArray.getDimension(R.styleable.HorizontalProgressBar_tipWidth, DensityUtil.dipToPixels(context, 105));
        mDotRadius = typedArray.getDimension(R.styleable.HorizontalProgressBar_dotRadius, DensityUtil.dipToPixels(context, 2.5f));
        mIndicateDotRadius = typedArray.getDimension(R.styleable.HorizontalProgressBar_indicateDotRadius, DensityUtil.dipToPixels(context, 3.5f));
        mProgressPaintH = typedArray.getDimension(R.styleable.HorizontalProgressBar_progressPaintH, DensityUtil.dipToPixels(context, 2));
        mProgressMarginTop = typedArray.getDimension(R.styleable.HorizontalProgressBar_progressMarginTop, DensityUtil.dipToPixels(context, 19));
        mScaleTextMarginTop = typedArray.getDimension(R.styleable.HorizontalProgressBar_scaleTextMarginTop, DensityUtil.dipToPixels(context, 2.5f));
        mSquareWidth = typedArray.getDimension(R.styleable.HorizontalProgressBar_squareWidth, DensityUtil.dipToPixels(context, 20));
        mShadowWidth = typedArray.getDimension(R.styleable.HorizontalProgressBar_shadowWidth, DensityUtil.dipToPixels(context, 5));
        mRoundRectRadius = typedArray.getDimension(R.styleable.HorizontalProgressBar_roundRectRadius, DensityUtil.dipToPixels(context, 2));
        mDuration = typedArray.getInteger(R.styleable.HorizontalProgressBar_duration, 1500);
        typedArray.recycle();

        mTipPaintWidth = DensityUtil.dipToPixels(context, 1);
        mTriangleHeight = DensityUtil.dipToPixels(context, 4);
        mTriangleVertexOne = DensityUtil.dipToPixels(context, 9);
        mTriangleVertexTwo = DensityUtil.dipToPixels(context, 8);
        mTriangleVertexThree = DensityUtil.dipToPixels(context, 15);
        mScaleTextLeftMargin = DensityUtil.dipToPixels(context, 5.5f);
        mScaleTextRightMargin = DensityUtil.dipToPixels(context, 5.5f);

        // view真实的高度
        mViewHeight = mTipHeight + mTipPaintWidth + mTriangleHeight + mProgressPaintH
                + mProgressMarginTop + mScaleTextMarginTop + mSquareWidth + mScaleTextH;
    }

    /**
     * 初始化画笔
     */
    private void initPaint() {
        mProgressBgPaint = getPaint(mProgressPaintH, mProgressBgColor, Paint.Style.STROKE);
        mProgressPaint = getPaint(mProgressPaintH, mProgressColor, Paint.Style.STROKE);
        mTipPaint = getPaint(mTipPaintWidth, mProgressColor, Paint.Style.FILL);
        mSquarePaint = getPaint(mTipPaintWidth, mProgressColor, Paint.Style.FILL);
        mDotPaint = getPaint(mDotRadius, mProgressColor, Paint.Style.FILL);
        mIndicateDotPaint = getPaint(mIndicateDotRadius, mIndicateDotColor, Paint.Style.FILL);

        initTextPaint();
    }

    /**
     * 初始化文字画笔
     */
    private void initTextPaint() {
        mTipTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTipTextPaint.setTextSize(mTipTextPaintSize);
        mTipTextPaint.setColor(Color.WHITE);
        mTipTextPaint.setTextAlign(Paint.Align.CENTER);
        mTipTextPaint.setAntiAlias(true);

        mScaleTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mScaleTextPaint.setTextSize(mTipTextPaintSize);
        // 必须加A, 否则不显示.
        mScaleTextPaint.setColor(mScaleTextColor);
        mScaleTextPaint.setTextAlign(Paint.Align.CENTER);
        mScaleTextPaint.setAntiAlias(true);
    }

    /**
     * 统一处理paint
     *
     * @param strokeWidth
     * @param color
     * @param style
     * @return
     */
    private Paint getPaint(float strokeWidth, int color, Paint.Style style) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStrokeWidth(strokeWidth);
        paint.setColor(color);
        paint.setAntiAlias(true);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStyle(style);

        return paint;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        setMeasuredDimension(measureWidth(widthMode, width), measureHeight(heightMode, height));
    }

    /**
     * 测量宽度
     *
     * @param mode
     * @param width
     * @return
     */
    private int measureWidth(int mode, int width) {
        switch (mode) {
            case MeasureSpec.UNSPECIFIED:
            case MeasureSpec.AT_MOST:
                break;
            case MeasureSpec.EXACTLY:
                mWidth = width;
                break;
        }
        return mWidth;
    }

    /**
     * 测量高度
     *
     * @param mode
     * @param height
     * @return
     */
    private int measureHeight(int mode, int height) {
        switch (mode) {
            case MeasureSpec.UNSPECIFIED:
            case MeasureSpec.AT_MOST:
                mHeight = (int) mViewHeight;
                break;
            case MeasureSpec.EXACTLY:
                mHeight = height;
                break;
        }
        return mHeight;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mLeftPos = getPaddingLeft() + mSquareWidth / 2 + mShadowWidth;
        mRightPos = getWidth() - mSquareWidth / 2 - mShadowWidth;

        /**
         * 如果不启动动画, 则执行下面获取当前进度条刻度所在位置.
         */
        if (!mEnableAnim) {
            float currentProgressDis = mProgress * (mWidth - mSquareWidth - mShadowWidth) / 100;
            if (mProgress == 0) {
                mMoveDis = currentProgressDis + mShadowWidth;
            } else {
                mMoveDis = currentProgressDis;
            }
        }

        // 绘制进度条
        canvas.drawLine(mLeftPos,
                mTipHeight + mProgressMarginTop,
                mRightPos,
                mTipHeight + mProgressMarginTop,
                mProgressBgPaint);

        canvas.drawLine(mLeftPos,
                mTipHeight + mProgressMarginTop,
                mMoveDis + mSquareWidth / 2,
                mTipHeight + mProgressMarginTop,
                mProgressPaint);


        // 绘制进度条上的圆点和矩形指示
        drawDotAndSquare(canvas);
        // 绘制提示框
        drawTipView(canvas);
        // 绘制进度条两遍的刻度文案
        drawScaleText(canvas);
    }

    /**
     * 绘制进度条上的小圆点以及正方形
     *
     * @param canvas
     */
    private void drawDotAndSquare(Canvas canvas) {
        // 绘制渐变
        mDotPaint.setShader(new LinearGradient(mLeftPos - mDotRadius
                , mTipHeight + mProgressMarginTop
                , mLeftPos + mDotRadius, mTipHeight + mProgressMarginTop
                , mGradientColors, null, Shader.TileMode.CLAMP));
        // 左圆点
        canvas.drawCircle(mLeftPos, mTipHeight + mProgressMarginTop, mDotRadius, mDotPaint);

        // 绘制渐变
        mDotPaint.setShader(new LinearGradient(mRightPos - mDotRadius, mTipHeight + mProgressMarginTop,
                mRightPos + mDotRadius, mTipHeight + mProgressMarginTop, mGradientColors, null, Shader.TileMode.CLAMP));
        // 右圆点
        canvas.drawCircle(mRightPos, mTipHeight + mProgressMarginTop, mDotRadius, mDotPaint);


        // 绘制周围光晕效果, 参数1是光晕圆弧的宽; 参数2, 3指的是光晕偏移量, 0标识不偏移, 居中.
        mSquarePaint.setShadowLayer(mShadowWidth, 0, 0, 0x806ba2f9);
        // 关闭硬件加速, 否则光晕无效.
        setLayerType(LAYER_TYPE_SOFTWARE, null);

        // 绘制正方形内部渐变
        mSquarePaint.setShader(new LinearGradient(mMoveDis
                , mTipHeight + mProgressMarginTop
                , mMoveDis + mSquareWidth
                , mTipHeight + mProgressMarginTop
                , mGradientColors, null, Shader.TileMode.CLAMP));

        // 绘制正方形位置形状
        mSquareRectF.set(mMoveDis
                , mTipHeight + mProgressMarginTop - mSquareWidth / 2
                , mMoveDis + mSquareWidth
                , mTipHeight + mProgressMarginTop + mSquareWidth / 2);

        // 绘制圆角正方形
        canvas.drawRoundRect(mSquareRectF
                , mRoundRectRadius
                , mRoundRectRadius
                , mSquarePaint);

        // 进度所在圆点
        canvas.drawCircle(mMoveDis + mSquareWidth / 2
                , mTipHeight + mProgressMarginTop
                , mIndicateDotRadius
                , mIndicateDotPaint);
    }

    /**
     * 绘制提示框
     *
     * @param canvas
     */
    private void drawTipView(Canvas canvas) {
        int baseline;
        // 绘制圆角矩形, 如果滑到右侧时, 空间不足以展示全提示框时, 翻转一下.
        if (getWidth() - mMoveDis <= mTipWidth) {
            // 绘制渐变
            mTipPaint.setShader(new LinearGradient(mMoveDis + mSquareWidth - mTipWidth, 0, mMoveDis + mSquareWidth, mTipHeight, mGradientColors, null, Shader.TileMode.CLAMP));
            mRectF.set(mMoveDis + mSquareWidth - mTipWidth, 0, mMoveDis + mSquareWidth, mTipHeight);

            // 绘制三角形
            mPath.moveTo(mMoveDis + mSquareWidth - mTriangleVertexOne * mTipWidth / mTipWidth, mTipHeight); // 右点
            mPath.lineTo(mMoveDis + mSquareWidth - mTriangleVertexTwo * mTipWidth / mTipWidth, mTipHeight + mTriangleHeight); // 顶点
            mPath.lineTo(mMoveDis + mSquareWidth - mTriangleVertexThree * mTipWidth / mTipWidth, mTipHeight); // 左点

            // 绘制提示文字
            mTipTextRect.left = (int) (mMoveDis + mSquareWidth - mTipWidth);
            mTipTextRect.top = 0;
            mTipTextRect.right = (int) (mMoveDis + mSquareWidth);
            mTipTextRect.bottom = (int) mTipHeight;
            Paint.FontMetricsInt fontMetrics = mTipTextPaint.getFontMetricsInt();
            baseline = (mTipTextRect.bottom + mTipTextRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
        } else {
            // 绘制渐变
            mTipPaint.setShader(new LinearGradient(mMoveDis, 0, mTipWidth + mMoveDis, mTipHeight, mGradientColors, null, Shader.TileMode.CLAMP));
            mRectF.set(mMoveDis, 0, mTipWidth + mMoveDis, mTipHeight);

            // 绘制三角形
            mPath.moveTo(mMoveDis + mTriangleVertexOne * mTipWidth / mTipWidth, mTipHeight); // 三角形左点
            mPath.lineTo(mMoveDis + mTriangleVertexTwo * mTipWidth / mTipWidth, mTipHeight + mTriangleHeight); // 三角形顶点
            mPath.lineTo(mMoveDis + mTriangleVertexThree * mTipWidth / mTipWidth, mTipHeight); // 三角形右点

            // 绘制提示文字
            mTipTextRect.left = (int) mMoveDis;
            mTipTextRect.top = 0;
            mTipTextRect.right = (int) (mTipWidth + mMoveDis);
            mTipTextRect.bottom = (int) mTipHeight;
            Paint.FontMetricsInt fontMetrics = mTipTextPaint.getFontMetricsInt();
            baseline = (mTipTextRect.bottom + mTipTextRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
        }

        canvas.drawRoundRect(mRectF, mRoundRectRadius, mRoundRectRadius, mTipPaint);
        canvas.drawPath(mPath, mTipPaint);
        // 文字绘制到整个布局的中心位置
        canvas.drawText(mTipText, mTipTextRect.centerX(), baseline, mTipTextPaint);
        mPath.reset();
    }

    /**
     * 绘制进度条底部左右两边文字
     */
    private void drawScaleText(Canvas canvas) {
        Paint.FontMetricsInt fontMetrics = mScaleTextPaint.getFontMetricsInt();
        int baseline = (mScaleTextRect.bottom + mScaleTextRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
        Paint.FontMetrics fm = mScaleTextPaint.getFontMetrics();
        mScaleTextH = fm.descent - fm.ascent;

        float LeftTextW = mScaleTextPaint.measureText(mLeftScaleText);
        // 左边刻度文字
        mScaleTextRect.left = getPaddingLeft() + mScaleTextLeftMargin;
        mScaleTextRect.top = (int) (mTipHeight + mProgressMarginTop + mSquareWidth / 2 + mScaleTextMarginTop);
        mScaleTextRect.right = (int) (getPaddingLeft() + mScaleTextLeftMargin + LeftTextW);
        mScaleTextRect.bottom = (int) (mTipHeight + mProgressMarginTop + mSquareWidth / 2 + mScaleTextH + mScaleTextMarginTop);
        canvas.drawText(mLeftScaleText, mScaleTextRect.centerX(), baseline, mScaleTextPaint);

        float rightTextW = mScaleTextPaint.measureText(mRightScaleText);
        // 右边
        mScaleTextRect.left = (int) (getWidth() - rightTextW - mScaleTextRightMargin);
        mScaleTextRect.top = (int) (mTipHeight + mProgressMarginTop + mSquareWidth / 2 + mScaleTextMarginTop);
        mScaleTextRect.right = getWidth() - mScaleTextRightMargin;
        mScaleTextRect.bottom = (int) (mTipHeight + mProgressMarginTop + mSquareWidth / 2 + mScaleTextH + mScaleTextMarginTop);
        canvas.drawText(mRightScaleText, mScaleTextRect.centerX(), baseline, mScaleTextPaint);
    }

    public HorizontalProgressBar setProgress(float progress) {
        mProgress = progress;
        return this;
    }

    /**
     * 设置指示框显示内容
     *
     * @param tips
     * @return
     */
    public HorizontalProgressBar setTips(String tips) {
        mTipText = tips;
        return this;
    }

    /**
     * 设置进度条刻度相关
     *
     * @param maxScale  最大刻度(最大期数)
     * @param scaleUnit 刻度单位(期)
     * @return
     */
    public HorizontalProgressBar setScale(int currentScale, int maxScale, String scaleUnit) {
        mLeftScaleText = MIN_SCALE + scaleUnit;
        mRightScaleText = maxScale + scaleUnit;

        mProgress = currentScale * 100.0f / maxScale;
        return this;
    }

    /**
     * 进度条渐进动画
     *
     * @param enableAnim
     */
    public void doAnimation(boolean enableAnim) {
        ValueAnimator valueAnimator;
        mEnableAnim = enableAnim;
        if (enableAnim) {
            valueAnimator = ValueAnimator.ofFloat(0, mProgress);
            valueAnimator.setDuration(mDuration);
            valueAnimator.setInterpolator(new LinearInterpolator());
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                private float mCurrentProgress;

                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    float value = (float) valueAnimator.getAnimatedValue();
                    if (TextUtils.isEmpty(mTipText)) {
                        // 进度数值只显示整数，我们自己的需求，可以忽略
                        mTipText = formatNum(format2Int(value));
                    }
                    // 把当前百分比进度转化成view宽度对应的比例
                    mCurrentProgress = value * (mWidth - mSquareWidth - mShadowWidth) / 100;
                    // 进度回调方法
                    if (mProgressListener != null) {
                        mProgressListener.currentProgressListener(value);
                    }
                    if (value == 0) {
                        mMoveDis = mCurrentProgress + mShadowWidth;
                    } else {
                        mMoveDis = mCurrentProgress;
                    }
                    invalidate();
                }
            });
            valueAnimator.start();
        }
    }

    /**
     * 回调监听事件
     *
     * @param listener
     * @return
     */
    public HorizontalProgressBar setProgressListener(ProgressListener listener) {
        mProgressListener = listener;
        return this;
    }

    /**
     * 回调接口
     */
    public interface ProgressListener {
        void currentProgressListener(float currentProgress);
    }
}
